#include "stdafx.h"

#include "InternetContext.h"
#include "Resource.h"

MainContext::MainContext() : ContextType(IctMain),
    Session(NULL),
    Connection(NULL),
    _callback(INTERNET_INVALID_STATUS_CALLBACK)
{
}

MainContext::~MainContext()
{
  if (Connection != NULL)
  {
    InternetCloseHandle(Connection);
  }

  if (Session != NULL)
  {
    InternetCloseHandle(Session);
  }
}

StickyTweetsStatus MainContext::Open(const CString& screenName, const CString& password, INTERNET_STATUS_CALLBACK callback)
{
  StickyTweetsStatus status(StatusStOk);

  if (!Session)
  {
    // Create Session handle and specify Async Mode
    Session = InternetOpen(L"StickyTweets", // User Agent
                                        INTERNET_OPEN_TYPE_PRECONFIG, // Preconfig or Proxy
                                        NULL, // proxy name
                                        NULL, // proxy bypass, do not bypass any address
                                        INTERNET_FLAG_ASYNC); // 0 for Synchronous
    if (!Session)
    {
      status = ErrorInternetOpen;
    }

    if (status == StatusStOk)
    {
      INTERNET_STATUS_CALLBACK callbackResult = InternetSetStatusCallback(Session, callback);

      if (callbackResult == INTERNET_INVALID_STATUS_CALLBACK)
      {
        status = ErrorInternetAsync;
      }
      else
      {
        _callback = callback;
      }
    }
  }

  if (status == StatusStOk && !Connection)
  {
    CString host;
    host.LoadString(IDS_URL_TWITTER);

    // Create Connection handle and provide context for async operations
    Connection = InternetConnect(Session,
                                           host.Mid(7),
                                           INTERNET_DEFAULT_HTTP_PORT,
                                           screenName,
                                           password,
                                           INTERNET_SERVICE_HTTP,
                                           0, // No special flags
                                           (DWORD_PTR)this); // Context to be used during the callbacks

    if (!Connection)
    {
      status = ErrorInternetConnect;
    }
  }

  return status;
}


StickyTweetsStatus MainContext::OpenSearch(INTERNET_STATUS_CALLBACK callback)
{
  StickyTweetsStatus status(StatusStOk);

  if (!Session)
  {
    // Create Session handle and specify Async Mode
    Session = InternetOpen(L"StickyTweets", // User Agent
                                        INTERNET_OPEN_TYPE_PRECONFIG, // Preconfig or Proxy
                                        NULL, // proxy name
                                        NULL, // proxy bypass, do not bypass any address
                                        INTERNET_FLAG_ASYNC); // 0 for Synchronous
    if (!Session)
    {
      status = ErrorInternetOpen;
    }

    if (status == StatusStOk)
    {
      INTERNET_STATUS_CALLBACK callbackResult = InternetSetStatusCallback(Session, callback);

      if (callbackResult == INTERNET_INVALID_STATUS_CALLBACK)
      {
        status = ErrorInternetAsync;
      }
      else
      {
        _callback = callback;
      }
    }
  }

  if (status == StatusStOk && !Connection)
  {
    CString host;
    host.LoadString(IDS_URL_SEARCH);

    // Create Connection handle and provide context for async operations
    Connection = InternetConnect(Session,
                                           host.Mid(7),
                                           INTERNET_DEFAULT_HTTP_PORT,
                                           NULL,
                                           NULL,
                                           INTERNET_SERVICE_HTTP,
                                           0, // No special flags
                                           (DWORD_PTR)this); // Context to be used during the callbacks

    if (!Connection)
    {
      status = ErrorInternetConnect;
    }
  }

  return status;
}

StickyTweetsStatus MainContext::Verify(const CString& screenName, const CString& password)
{
  return Open(screenName, password, _callback);
}

StickyTweetsStatus MainContext::Close()
{
  if (InternetCloseHandle(Connection))
  {
    Connection = 0;

    InternetSetStatusCallback(Session, INTERNET_INVALID_STATUS_CALLBACK);
    if (InternetCloseHandle(Session))
    {
      Session = 0;
      return StatusStOk;
    }
  }

  return ErrorInternetConnection;
}

RequestContext::RequestContext(MainContext* pMainContext) : ContextType(IctRequest),
    Main(pMainContext),
    Request(NULL),
    Type(RtUnknown),
    Status(StatusStOk),
    DownloadedSize(InvalidDownloadSize),
    ReadSize(0),
    WrittenSize(0),
    ReadOffset(0),
    WriteOffset(0),
    PendingWrites(0),
    ReceiveDone(FALSE)
{
}

StickyTweetsStatus RequestContext::SendRequest(RequestType type, CString resource, CString query)
{
  ATLTRACE2(L"SendRequest: %s\n", resource.GetString());
  StickyTweetsStatus status(StatusStOk);

  Type = type;
  Query = query;

  if (status == StatusStOk)
  {
    InitializeCriticalSection(&CriticalSection);

    Request = HttpOpenRequest(Main->Connection,
                                       L"GET", //GET or POST
                                       resource,
                                       NULL, // Use default HTTP/1.1 as the version
                                       NULL, //Do not provide any referrer
                                       NULL, //Do not provide Accept types
                                       INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE,
                                       (DWORD_PTR)this);
    if (!Request)
    {
      status = ErrorInternetOpenRequest;
    }
  
    ATLTRACE2(L" Created HINTERNET %x\n", Request);
  }

  if (status == StatusStOk)
  {
    BOOL requestSuccess = HttpSendRequest(Request,
                                      NULL, // do not provide additional Headers
                                      0, // dwHeadersLength 
                                      NULL, // Do not send any data 
                                      0); // dwOptionalLength

    if (!requestSuccess && GetLastError() != ERROR_IO_PENDING)
    {
      status = ErrorInternetSendRequest;
    }
  }

  return status;
}

RequestContext::~RequestContext()
{

}